package socks

import (
	"bufio"
	"encoding/binary"
	"sync"
	"sync/atomic"
	"time"

	"gitee.com/cjianwen/go/iohelper"
)

type IPackHelper[T any] interface {
	ReadPack(rd *iohelper.ReadHelper, pack *T) (err error)
	WritePack(w *iohelper.WriteHelper, pack *T) (err error)
}

type packData[T, U any] struct {
	pack *T
	conn *ConnClient[T, U] // 当前消息的连接
	next *packData[T, U]
}

type PackDataHandler[T, U any] func(conn *ConnClient[T, U], pack *T)

type MsgClient[T any, U any] struct {
	*ConnClient[T, U]
	client *SocketClient
}

func (mc *MsgClient[T, U]) Connected() bool {
	return mc.client.Connected()
}

func (mc *MsgClient[T, U]) GetConn() *ConnClient[T, U] {
	return mc.ConnClient
}

// T 为包信息， H 为包的解析类  U 为 conn 的用户定制数据，方便操作连接
type MsgReceiver[T any, H IPackHelper[T], U any] struct {
	first, last  *packData[T, U]
	locker       FastLocker
	Clients      sync.Map         // int, *ConnClient
	byteOrd      binary.ByteOrder // 大小端，默认小端
	helper       H
	pool         sync.Pool
	sock         sockOwner
	isServed     atomic.Bool
	OnConnect    func(conn *ConnClient[T, U])
	OnDisconnect func(conn *ConnClient[T, U])
	OnReadPack   func(conn *ConnClient[T, U], pack *T) // 这个事件是在 go rount 中触发发，一个连接一个 go rount
}

func (m *MsgReceiver[T, H, U]) addPack(pack *packData[T, U]) {
	m.locker.Lock()
	defer m.locker.Unlock()
	// pack.next = nil  没用
	if m.first == nil {
		m.first = pack
		m.last = pack
	} else {
		m.last.next = pack
		m.last = pack
	}
}

func (m *MsgReceiver[T, H, U]) extractPacks() (pack *packData[T, U]) {
	m.locker.Lock()
	defer m.locker.Unlock()
	pack = m.first
	m.first = nil
	m.last = nil
	return pack
}

func (m *MsgReceiver[T, H, U]) HandlePacks(handleFun PackDataHandler[T, U]) {
	pack := m.extractPacks()

	var next *packData[T, U]
	for pack != nil {
		next = pack.next
		handleFun(pack.conn, pack.pack)

		pack.pack = nil
		pack.conn = nil
		pack.next = nil
		m.pool.Put(pack) // 重新 放回缓存

		pack = next
	}
}

func (m *MsgReceiver[T, H, U]) readPacks(client *ConnClient[T, U]) {
	for {
		p := new(T)
		err := m.helper.ReadPack(client.reader, p)
		if err != nil {
			// m.sock.procSockError(client.SockConn, err)   // 关闭的时候 sock 为空了，所以这里不能要
			break
		}

		if m.OnReadPack != nil {
			m.OnReadPack(client, p)
			continue // 有事件处理了就不用再分发了
		}

		pack := m.pool.Get().(*packData[T, U])
		pack.conn = client
		pack.pack = p
		m.addPack(pack)
	}
}

func (m *MsgReceiver[T, H, U]) procSocketRead(conn *SockConn, reader *bufio.Reader) {
	client := conn.GetData().(*ConnClient[T, U])

	defer func() {
		// if err := recover().(error); err != nil {
		// 	m.sock.procSockError(conn, err) // 加上异常处理
		// }

		m.Clients.Delete(conn.GetId())

		if m.OnDisconnect != nil {
			m.OnDisconnect(client)
		}
	}()

	m.readPacks(client)
}

func (m *MsgReceiver[T, H, U]) serve(owner sockOwner) {
	m.CloseServe()

	m.sock = owner
	sock := owner.getSockBase()

	sock.SocketReadHnalder = m.procSocketRead

	ch := sock.ConnectHandler // 重写连接事件
	sock.ConnectHandler = func(conn *SockConn) {
		client := &ConnClient[T, U]{
			SockConn:   conn,
			writer:     iohelper.NewWriteHelper(conn, m.byteOrd),
			qWriter:    iohelper.NewWriteHelper(conn.sendq, m.byteOrd),
			reader:     iohelper.NewReadHelper(conn.readBuff, m.byteOrd),
			packWriter: m.helper}

		conn.SetData(client)

		m.Clients.Store(conn.GetId(), client) // 这里存储起来
		if m.OnConnect != nil {
			m.OnConnect(client)
		}

		if ch != nil {
			ch(conn)
		}
	}

	m.isServed.Store(true)

	go func() { // 自动发送队列里面的数据
		sock := m.sock
		for m.isServed.Load() {
			sock.SendQueueDatas()
			time.Sleep(time.Millisecond)
		}
	}()
}

func (m *MsgReceiver[T, H, U]) ListenAndServe(port uint16) (err error) {
	server := NewSocketServer(port)
	m.serve(server)
	return server.Open()
}

// demo: addr = "127.0.0.1:6688"，这是一个异步方法，需要等待连接成功后才可以使用
func (m *MsgReceiver[T, H, U]) ConnectTo(connAddr string) *MsgClient[T, U] {
	client := NewSocketClient(connAddr)

	ret := &MsgClient[T, U]{client: client}

	oldConn := m.OnConnect
	m.OnConnect = func(conn *ConnClient[T, U]) {
		ret.ConnClient = conn
		oldConn(conn)
	}

	oldDisconn := m.OnDisconnect
	m.OnDisconnect = func(conn *ConnClient[T, U]) {
		ret.ConnClient = nil
		oldDisconn(conn)
	}

	m.serve(client)

	client.Open()

	return ret
}

func (m *MsgReceiver[T, H, U]) CloseServe() {
	if m.isServed.CompareAndSwap(true, false) {
		if m.sock != nil {
			m.sock.Close()
			m.sock = nil
		}
	}
}

// var errPackHelperIsNil = errors.New("packhelper is nil")

// 创建一个消息接收器， 消息接收器需要一个创建消息头的回调函数
func NewMsgReceiver[T any, H IPackHelper[T], U any](packHelper H, userData U, byteOrd binary.ByteOrder) *MsgReceiver[T, H, U] {
	msgReceiver := &MsgReceiver[T, H, U]{
		byteOrd: byteOrd,
		helper:  packHelper,
		pool: sync.Pool{
			New: func() any {
				return new(packData[T, U])
			}},
	}
	return msgReceiver
}

type ConnClient[T, U any] struct {
	*SockConn
	reader     *iohelper.ReadHelper
	writer     *iohelper.WriteHelper
	qWriter    *iohelper.WriteHelper // 往队列写的 writer
	packWriter IPackHelper[T]

	Data U
}

// 直接发送包
func (c *ConnClient[T, U]) SendPack(pack *T) error {
	return c.packWriter.WritePack(c.writer, pack)
}

// 通过队列发送，异步写，避免主线程阻塞
func (c *ConnClient[T, U]) SendPackToQueue(pack *T) error {
	return c.packWriter.WritePack(c.qWriter, pack)
}

func (c *ConnClient[T, U]) Connected() bool { // 连接是否正常
	return !c.isClose.Load()
}
